/**
 * 
 */
package com.et114.modules.products.services;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.lang.StringUtils;

import com.et114.core.utility.ArgumentTokenizer;
import com.et114.core.utility.SQLParser;
import com.et114.modules.products.vo.PropertyData;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.opensymphony.module.propertyset.AbstractPropertySet;
import com.opensymphony.module.propertyset.InvalidPropertyTypeException;
import com.opensymphony.module.propertyset.PropertyException;
import com.opensymphony.module.propertyset.PropertySet;

/*
 * @author guanhw
 */
public class ProPropertySetImp extends AbstractPropertySet {
	public ProPropertySetImp ( ) {
		// TODO Auto-generated constructor stub
	}
	protected Log log = LogFactory.getLog( this.getClass( ) );
	protected String								globalKey;
	protected SqlMapClient							sqlMapClient;
	
	public void setSqlMapClient ( SqlMapClient sqlMapClient ) {
		this.sqlMapClient = sqlMapClient;
	}
	
	public SqlMapClient getSqlMapClient ( ) {
		return sqlMapClient;
	}
	
	@ SuppressWarnings ( "unchecked" )
	public Collection getKeys ( String prefix , int type )
			throws PropertyException {
		if ( prefix == null ) {
			prefix = "";
		}
		
		SqlMapClient mapper = getSqlMapClient ( );
		try {
			Map param = new HashMap ( );
			param.put ( "prefix" , prefix );
			param.put ( "globalKey" , globalKey );
			if ( type != 0 ) {
				param.put ( "itemType" , new Integer ( type ) );
			}
			List list = mapper.queryForList ( "selectProperty" , param );
			return list;
		} catch ( Exception e ) {
			throw new PropertyException ( e.getMessage ( ) );
		}
	}
	
	@ SuppressWarnings ( "unchecked" )
	public List< PropertyData > selectProperty4Search( java.util.Map < String , String > params ) throws Exception {
		if ( params == null || params.size ( ) == 0  ) 
			throw new Exception( this.getClass ( ) + ":::Param is NULL !" ) ; 
		
		SqlMapClient mapper = getSqlMapClient ( );
		return  mapper.queryForList ( "selectProperty4Search" , params ) ; 
	}
	
	@ SuppressWarnings ( "unchecked" )
	public List< PropertyData > selectProperty4Search2( java.util.List < String > params ) throws Exception {
		if ( params == null || params.size ( ) == 0  ) 
			throw new Exception( this.getClass ( ) + ":::Param is NULL !" ) ; 
		
		SqlMapClient mapper = getSqlMapClient ( );
		return  mapper.queryForList ( "selectProperty4Search2" , params ) ; 
	}	
	
	
	@ SuppressWarnings ( "unchecked" )
	public List< PropertyData > selectProperty4Search3( PropertyData propertyData ) throws Exception {
		SqlMapClient mapper = getSqlMapClient ( );
		return  mapper.queryForList ( "selectProperty4Search3" , propertyData ) ; 
	}		
	
	@ SuppressWarnings ( "unchecked" )
	public int getType ( String key ) throws PropertyException {
		SqlMapClient mapper = getSqlMapClient ( );
		try {
			Map param = new HashMap ( );
			param.put ( "globalKey" , globalKey );
			param.put ( "itemKey" , key );
			PropertyData data = ( PropertyData ) mapper.queryForObject (
					"selectProperty" , param );
			log.debug ( "query type: " + data.getItemType ( ) );
			
			return data.getItemType ( );
		} catch ( Exception e ) {
			throw new PropertyException ( e.getMessage ( ) );
		}
	}
	
	public boolean exists ( String key ) throws PropertyException {
		return getType ( key ) != 0;
	}
	
	@ SuppressWarnings ( "unchecked" )
	public void init ( Map config , Map args ) {
		globalKey = ( String ) args.get ( "globalKey" );
		setSqlMapClient ( ( SqlMapClient ) args.get ( "sqlMapClient" ) );
	}
	
	
	
	public void remove ( String key ) throws PropertyException {
		SqlMapClient mapper = getSqlMapClient ( );
		try {
			PropertyData data = new PropertyData ( );
			data.setGlobalKey ( globalKey );
			data.setItemKey ( key );
			
			log.debug ( "globalKey:" + globalKey + ";" + key ) ;
			int i = mapper.delete ( "deleteProperty" , data );
			log.info ( "delete property key: " + data.getItemKey ( )
					+ ", affected rows: " + i );
		} catch ( Exception e ) {
			throw new PropertyException ( e.getMessage ( ) );
		}
	}
	
	public void setImpl ( int type , String key , Object value )
			throws PropertyException {
		if ( value == null ) {
			throw new PropertyException (
					"IBatisPropertySet does not allow for null values to be stored" );
		}
		
		SqlMapClient mapper = getSqlMapClient ( );
		try {
			PropertyData data = new PropertyData ( );
			data.setGlobalKey ( globalKey );
			data.setItemKey ( key );
			data.setItemType ( type );
			setValues ( data , type , key , value );
			
			log.debug ( "execute updata: updateProperty" );
			int rows = mapper.update ( "updateProperty" , data );
			log.debug ( "affected rows: " + rows );
			
			if ( rows != 1 ) {
				// ok, this is a new value, insert it
				log.debug ( "execute insert insertProperty" );
				mapper.insert ( "insertProperty" , data );
				log.debug ( "inserted object" );
			}
		} catch ( Exception e ) {
			log.error ( e.getMessage ( ) , e ) ;
			throw new PropertyException ( e.getMessage ( ) );
		}
	}
	
	@ SuppressWarnings ( "unchecked" )
	public Object get ( int type , String key ) throws PropertyException {
		Object o = null;
		SqlMapClient mapper = getSqlMapClient ( );
		try {
			Map param = new HashMap ( );
			param.put ( "globalKey" , globalKey );
			param.put ( "itemKey" , key );
			PropertyData data = ( PropertyData ) mapper.queryForObject (
					"selectProperty" , param );
			log.debug ( "result: " + data + ", type: " + data.getItemType ( ) );
			
			if ( data.getItemType ( ) != type ) {
				throw new InvalidPropertyTypeException ( );
			}
			
			switch ( type ) {
				case PropertySet.BOOLEAN :
					int boolVal = data.getNumberValue ( ).intValue ( );
					o = new Boolean ( boolVal == 1 );
					break;
				case PropertySet.TEXT :
					o = data.getDataValue ( );
					;
					break;
				case PropertySet.DATE :
					o = data.getDateValue ( );
					break;
				case PropertySet.DOUBLE :
					o = data.getFloatValue ( );
					break;
				case PropertySet.INT :
					o = data.getNumberValue ( );
					break;
				case PropertySet.LONG :
					o = data.getNumberValue ( );
					break;
				case PropertySet.STRING :
					o = data.getStringValue ( );
					break;
				default :
					throw new InvalidPropertyTypeException (
							"IBatisPropertySet doesn't support this type yet." );
			}
		} catch ( Exception e ) {
			throw new PropertyException ( e.getMessage ( ) );
		}
		log.debug ( "return object: " + o );
		return o;
	}
	
	private void setValues ( PropertyData data , int type , String key ,
			Object value ) throws PropertyException {
		switch ( type ) {
			case PropertySet.BOOLEAN :
				Boolean boolVal = ( Boolean ) value;
				data.setNumberValue ( boolVal.booleanValue ( ) ? BigDecimal
						.valueOf ( 1L ) : BigDecimal.valueOf ( 0L ) );
				break;
			
			case PropertySet.TEXT :
				data.setDataValue ( value.toString ( ) );
				break;
			
			case PropertySet.DATE :
				Date date = ( Date ) value;
				data.setDateValue ( date );
				break;
			
			case PropertySet.DOUBLE :
				Double d = ( Double ) value;
				data.setFloatValue ( new Float ( d.floatValue ( ) ) );
				break;
			
			case PropertySet.INT :
				Integer i = ( Integer ) value;
				data.setNumberValue ( java.math.BigDecimal.valueOf ( i
						.intValue ( ) ) );
				break;
			
			case PropertySet.LONG :
				Long l = ( Long ) value;
				data.setNumberValue ( java.math.BigDecimal.valueOf ( l
						.intValue ( ) ) );
				break;
			
			case PropertySet.STRING :
				data.setStringValue ( ( String ) value );
				break;
			
			default :
				throw new PropertyException ( "This type isn't supported!" );
		}
	}
	
	

	public String getGlobalKey ( ) {
		return globalKey;
	}

	public void setGlobalKey ( String globalKey ) {
		this.globalKey = globalKey;
	}

	public void remove ( ) throws PropertyException {
		// TODO Auto-generated method stub
		SqlMapClient mapper = getSqlMapClient ( );
		try {
			PropertyData data = new PropertyData ( );
			data.setGlobalKey ( globalKey );
			mapper.delete ( "deleteProperty" , data );
		} catch ( Exception e ) {
			throw new PropertyException ( e.getMessage ( ) );
		}
		
	}
	
	
	
	
	
	//DISTINCT ( SUBSTRING( ( GLOBAL_KEY )   ,3 , LENGTH( GLOBAL_KEY ) ) )
	// distinct( e" + count + ".GLOBAL_KEY )
	private String generateBaseSql( int count , String itemKey ) {
		return "SELECT  DISTINCT ( SUBSTRING( ( e" + count + ".GLOBAL_KEY )   ,3 , LENGTH( e" + count + ".GLOBAL_KEY ) ) ) as globalKey FROM " +
					" B_PROPERTYDATA e" + count + "  WHERE  e" + count + ".ITEM_KEY ='" + SQLParser.transactSQLInjection (  itemKey ) + "' " ; 
	}
	
	private String generateExistSql( String sql  , int count  ) {
		return "  AND EXISTS( " + sql + " AND e" + count + ".GLOBAL_KEY = e"
				+ ( count - 1 ) + ".GLOBAL_KEY )";
	}
	
	public String generateSql( String params  ) { 
		String sql = null  ; 
		Map< String , String  > paramsMap = new TreeMap< String , String >( ) ; 
		if ( !StringUtils.isEmpty ( params ) && !StringUtils.isBlank ( params )  ) {
			ArgumentTokenizer ats = new ArgumentTokenizer( params , ';' ) ; 
			while (  ats.hasNext ( ) ) {
				String ass = ats.next ( ) ; 
				ArgumentTokenizer as = new ArgumentTokenizer( ass , ':' ) ;
				while( as.hasNext ( ) ) {
					String key = as.next ( ) ; 
					String value = as.next ( ) ; ;
					paramsMap.put ( key , value ) ; 
				}
			}
		}			
		
		
		if ( paramsMap .size ( )  > 0  ) {
			int flg = 0 ; 
			for ( java.util.Iterator <  String >  iter = paramsMap.keySet ( ).iterator ( ) ; iter.hasNext ( ) ;  ) {
				flg ++ ; 
				String key = iter.next ( ) ; 
				if ( paramsMap.size ( ) == 1  ) {
					return generateBaseSql( flg , key  )  ; 
				} 
				else {
					if ( flg == 1 ) {  // 
						sql = generateBaseSql( flg , key  ) ; 
					} 
				
					else {
						sql =  generateBaseSql( flg , key  ) +  generateExistSql ( sql , flg ) ;
					}
				}
			}
		}
		return sql ; 
	}
	
	
	private String generateBaseSql2( int count , String itemKey ) {
		return "SELECT  distinct( e" + count + ".GLOBAL_KEY ) as globalKey FROM " +
					" B_PROPERTYDATA e" + count + "  WHERE  e" + count + ".ITEM_KEY ='" + SQLParser.transactSQLInjection (  itemKey ) + "' " ; 
	}
	
	private String generateExistSql2( String sql  , int count  ) {
		return "  AND EXISTS( " + sql + " AND e" + count + ".GLOBAL_KEY = e"
				+ ( count - 1 ) + ".GLOBAL_KEY )";
	}
	
	public String generateSql2( String params  ) { 
		String sql = null  ; 
		Map< String , String  > paramsMap = new TreeMap< String , String >( ) ; 
		if ( !StringUtils.isEmpty ( params ) && !StringUtils.isBlank ( params )  ) {
			ArgumentTokenizer ats = new ArgumentTokenizer( params , ';' ) ; 
			while (  ats.hasNext ( ) ) {
				String ass = ats.next ( ) ; 
				ArgumentTokenizer as = new ArgumentTokenizer( ass , ':' ) ;
				while( as.hasNext ( ) ) {
					String key = as.next ( ) ; 
					String value = as.next ( ) ; ;
					paramsMap.put ( key , value ) ; 
				}
			}
		}			
		
		
		if ( paramsMap .size ( )  > 0  ) {
			int flg = 0 ; 
			for ( java.util.Iterator <  String >  iter = paramsMap.keySet ( ).iterator ( ) ; iter.hasNext ( ) ;  ) {
				flg ++ ; 
				String key = iter.next ( ) ; 
				if ( paramsMap.size ( ) == 1  ) {
					return generateBaseSql2( flg , key  )  ; 
				} 
				else {
					if ( flg == 1 ) {  // 
						sql = generateBaseSql2( flg , key  ) ; 
					} 
				
					else {
						sql =  generateBaseSql2( flg , key  ) +  generateExistSql2 ( sql , flg ) ;
					}
				}
			}
		}
		return sql ; 
	}
	
	
	public static void main( String[] s ) {
		ProPropertySetImp ppsi = new ProPropertySetImp( ) ; 
		String params = ";1:2;3:4;4:5;" ; 
		System.out.println ( ppsi.generateSql ( params ) ) ;
	}
	
	/*
	public void generateSqlByParams ( String params , String sql , Map< String , String > paramsMap )
			throws Exception {
		String base = "SELECT  distinct( GLOBAL_KEY ) as globalKey FROM "
				+ " B_PROPERTYDATA WHERE  ITEM_KEY =";
		if ( ! StringUtils.isEmpty ( params )
				&& ! StringUtils.isBlank ( params ) ) {
			int flg = 0;
			ArgumentTokenizer ats = new ArgumentTokenizer ( params , ';' );
			while (ats.hasNext ( )) {
				String ass = ats.next ( );
				ArgumentTokenizer as = new ArgumentTokenizer ( ass , ':' );
				while (as.hasNext ( )) {
					String key = as.next ( );
					String value = as.next ( );
					paramsMap.put ( key , value );
					flg ++ ;
					if ( flg == 1 )
						sql = base + "'" + key + "'";
					else
						sql = base + "'" + key + "'" + " AND GLOBAL_KEY IN ( "
								+ sql + ")";
					
				}
			}
		}
	}*/
}
